/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * https://zhiqim.org/project/zhiqim_framework/zhiqim_kernel.htm
 *
 * Zhiqim Kernel is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.kernel.util;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CodingErrorAction;

import javax.imageio.ImageIO;

import org.zhiqim.kernel.annotation.AnAlias;
import org.zhiqim.kernel.constants.CodeConstants;
import org.zhiqim.kernel.constants.EnumConstants;
import org.zhiqim.kernel.enumerated.LetterCase;
import org.zhiqim.kernel.model.mutables.MInt;

/**
 * Bit/Byte组装类 BigEndian 存储时高位在前，低位在后，可读性高，优先知道该值的正负情况，以网络传输、IBM、Motorola CPU为主
 * LittleEndian 存储时低位在前，高位在后，利于对值进行计算，如加减等操作时位运算次数更少，以Intel、DEC CPU为主
 * 
 * 有值0x12345678，使用大小端在内存中地址位置 BigEndian LittleEndian byte[0] 0x0000 0x12 0x78
 * byte[1] 0x0001 0x34 0x56 byte[2] 0x0002 0x56 0x34 byte[3] 0x0003 0x78 0x12
 * 
 * BigEndian 0x12345678 = 0x00000078 + 0x00005600 + 0x00340000 + 0x12000000 =
 * byte[3]<<0 + byte[2]<<8 + byte[1]<<16 + byte[0]<<24
 * 
 * LitEndian 0x12345678 = 0x00000078 + 0x00005600 + 0x00340000 + 0x12000000 =
 * byte[0]<<0 + byte[1]<<8 + byte[2]<<16 + byte[3]<<24
 * 
 * 由于Java中byte取值为-127 - 128，因此在作位运算前需转化为0-256 即byte[?] & 0xFF
 * 
 * @version v1.0.0 @author zouzhigang 2014-2-27 新建与整理
 */
@AnAlias("Bytes")
public class Bytes implements CodeConstants, EnumConstants
{
    public static final Bytes BU = new Bytes(true, _UTF_8_);
    public static final Bytes BG = new Bytes(true, _GBK_);
    public static final Bytes BI = new Bytes(true, _ISO_8859_1_);
    public static final Bytes LU = new Bytes(false, _UTF_8_);
    public static final Bytes LG = new Bytes(false, _GBK_);
    public static final Bytes LI = new Bytes(false, _ISO_8859_1_);

    private Charset encoding = _UTF_8_C_;
    private boolean isBigEndian = true;

    public Bytes()
    {
    }

    public Bytes(boolean isBigEndian)
    {
        this.isBigEndian = isBigEndian;
    }

    public Bytes(String encoding)
    {
        this.encoding = Charset.forName(encoding);
    }

    public Bytes(boolean isBigEndian, String encoding)
    {
        this.isBigEndian = isBigEndian;
        this.encoding = Charset.forName(encoding);
    }

    /**********************************************************/
    // 以下方法为在给定的偏移位,从指定的字节数组获取数据的方法
    /**********************************************************/

    /** 从字节数组b中 根据偏移量offset读取一个双字节的char */
    public char getChar2(byte[] b, MInt off)
    {
        int offset = off.value;
        off.value += 2;

        return getChar2(b, offset);
    }

    /** 从字节数组b中 根据偏移量offset读取一个short */
    public short getShort(byte[] b, MInt off)
    {
        int offset = off.value;
        off.value += 2;

        return getShort(b, offset);
    }

    /** 从字节数组b中 根据偏移量offset读取一个unsigned short */
    public int getShortUnsigned(byte[] b, MInt off)
    {
        int offset = off.value;
        off.value += 2;

        return getShortUnsigned(b, offset);
    }

    /** 从字节数组b中 根据偏移量offset读取一个int */
    public int getInt(byte[] b, MInt off)
    {
        int offset = off.value;
        off.value += 4;

        return getInt(b, offset);
    }

    /** 从字节数组b中 根据偏移量offset读取一个unsigned int */
    public long getIntUnsigned(byte[] b, MInt off)
    {
        int offset = off.value;
        off.value += 4;

        return getIntUnsigned(b, offset);
    }
    
    /**
     * 从字节数组b中，根据偏移量offset读取一个Zigzag的int型<br>
     * （Zigzag，使用高1位表示组包标志位，0表示结束，1表示后续还有）
     */
    public static int getIntZigzag(byte[] b, MInt off)
    {
        int val = 0, bit = 0;
        for (;off.value<b.length;off.value++,bit+=7)
        {
            byte v = b[off.value];
            if (Bits.isZero(v, 1))
            {//如果第一位是0，表示结束
                val |= (v << bit);
                break;
            }
            
            //如果第一位是1，表示后续字节还是该整型
            val |= ((v & 0x7F) << bit);
        }
        off.value++;
        return val;
    }

    /** 从字节数组b中 根据偏移量offset读起一个float */
    public float getFloat(byte[] b, MInt off)
    {
        int offset = off.value;
        off.value += 4;

        return getFloat(b, offset);
    }

    /** 从字节数组b中 根据偏移量offset读起一个long */
    public long getLong(byte[] b, MInt off)
    {
        int offset = off.value;
        off.value += 8;

        return getLong(b, offset);
    }

    /** 从字节数组b中 根据偏移量offset读起一个double */
    public double getDouble(byte[] b, MInt off)
    {
        int offset = off.value;
        off.value += 8;

        return getDouble(b, offset);
    }

    /** 从字节数组b中 根据偏移量offset读起字符串 */
    public String getString(byte[] b, MInt off)
    {
        off.value = b.length;
        return new String(b, off.value, b.length-off.value, encoding);
    }
    
    /**
     * 从字节数组b中 根据偏移量offset读起一个到结束符为value的String
     * 
     * @param b         字节数组
     * @param off       偏移量
     * @param val       结束符
     * @return          返回一个String
     */
    public String getString(byte[] b, MInt off, char val)
    {
        return getString(b, off, (byte)val);
    }

    /**
     * 从字节数组b中 根据偏移量offset读起一个到结束符为value的String
     * 
     * @param b         字节数组
     * @param off       偏移量
     * @param val       结束符
     * @return          返回一个String
     */
    public String getString(byte[] b, MInt off, byte val)
    {
        int offset = off.value;
        int i = offset;
        int len = b.length;
        while (i < len)
        {//找到结束符直到最后
            if (b[i] == val)
                break;

            i++;
        }

        byte[] tmp = new byte[i - offset];
        System.arraycopy(b, offset, tmp, 0, i - offset);
        String str = new String(tmp, encoding);

        off.value = i+1;
        return str;
    }

    /**
     * 从字节数组b中 根据偏移量offset读起一个定长的String，遇到\0结束
     * 
     * @param b         字节数组
     * @param off       偏移量
     * @param len       长度
     * @return          返回一个String
     */
    public String getString(byte[] b, MInt off, int len)
    {
        int offset = off.value;
        int i = 0;
        while (i < len)
        {
            if (offset + i >= b.length)
                break;
            if (b[offset + i] == 0)
                break;//遇到\0结束
            i++;
        }

        byte[] tmp = new byte[i];
        System.arraycopy(b, offset, tmp, 0, i);
        String str = new String(tmp, encoding);

        off.value += len;
        return str;
    }

    /**
     * 从字节数组b中 根据偏移量offset读起一个定长的String，遇到\0结束
     * 
     * @param b         字节数组
     * @param off       偏移量
     * @param len       长度
     * @param hasEnd    有结束符
     * @return          返回一个String
     */
    public String getString(byte[] b, MInt off, int len, boolean hasEnd)
    {
        int offset = off.value;
        int i = 0;
        while (i < len)
        {
            if (offset + i >= b.length)
                break;
            if (b[offset + i] == 0)
                break;//遇到\0结束
            i++;
        }

        byte[] tmp = new byte[i];
        System.arraycopy(b, offset, tmp, 0, i);
        String str = new String(tmp, encoding);

        if (hasEnd)
            off.value += len+1;
        else
            off.value += len;
        return str;
    }

    /**********************************************************/
    // 以下方法为在指定的偏移位,和值,插入到指定的字节数组的方法
    /**********************************************************/

    /** 插入一个 <b>双字节</b> 的char */
    public void putChar2(byte[] b, MInt off, char val)
    {
        off.value = putChar2(b, off.value, val);
    }

    /** 插入一个short */
    public void putShort(byte[] b, MInt off, short val)
    {
        off.value = putShort(b, off.value, val);
    }

    /** 插入一个int只保留两字节，多用于无符号短整型 */
    public void putShort(byte[] b, MInt off, int val)
    {
        putShort(b, off, (short)val);
    }

    /** 插入一个int */
    public void putInt(byte[] b, MInt off, int val)
    {
        off.value = putInt(b, off.value, val);
    }
    
    /** 插入一个long只留4字节，多用于无符号整型 */
    public void putInt(byte[] b, MInt off, long val)
    {
        off.value = putInt(b, off.value, (int)val);
    }
    
    /** 插入一个float */
    public void putFloat(byte[] b, MInt off, float val)
    {
        off.value = putFloat(b, off.value, val);
    }

    /** 插入一个long */
    public void putLong(byte[] b, MInt off, long val)
    {
        off.value = putLong(b, off.value, val);
    }

    /** 插入一个double */
    public void putDouble(byte[] b, MInt off, double val)
    {
        off.value = putDouble(b, off.value, val);
    }

    /** 插入一个不定长的String,由str.getBytes().length来计算,无结束符 */
    public void putString(byte[] b, MInt off, String str)
    {
        if (Validates.isEmpty(str))
            return;

        byte[] ret = str.getBytes(encoding);
        System.arraycopy(ret, 0, b, off.value, ret.length);
        off.value += ret.length;
    }

    /**
     * 插入一个定长的String,无结束符<br>
     * 
     * @param b         字节数组
     * @param offset    偏移量
     * @param str       字节串
     * @param len       长度
     */
    public void putString(byte[] b, MInt off, String str, int len)
    {
        if (Validates.isEmpty(str))
        {//为空偏移len
            off.value  += len;
            return;
        }
        
        byte[] ret = str.getBytes(encoding);

        if (ret.length >= len)
            System.arraycopy(ret, 0, b, off.value, len);
        else
            System.arraycopy(ret, 0, b, off.value, ret.length);

        off.value += len;
    }

    /**
     * 插入一个定长的String, 值为对象型（int,long等）指定长度，不足长度的，以pad填充<br>
     * 
     * @param b         字节数组
     * @param offset    偏移量
     * @param val       对象，put时String.valueOf(val)
     * @param len       长度
     * @param pad       填充符
     */
    public void putString(byte[] b, MInt off, Object val, int len, char pad)
    {
        putString(b, off, String.valueOf(val), len, (byte)pad);
    }
    
    /**
     * 插入一个定长的String, 指定长度，不足长度的，以pad填充<br>
     * 
     * @param b         字节数组
     * @param offset    偏移量
     * @param str       字节串
     * @param len       长度
     * @param pad       填充符
     */
    public void putString(byte[] b, MInt off, String str, int len, char pad)
    {
        putString(b, off, str, len, (byte)pad);
    }
    
    /**
     * 插入一个定长的String, 指定长度，不足长度的，以pad填充<br>
     * 
     * @param b         字节数组
     * @param offset    偏移量
     * @param str       字节串
     * @param len       长度
     * @param pad       填充符
     */
    public void putString(byte[] b, MInt off, String str, int len, byte pad)
    {
        if (Validates.isEmpty(str))
        {//为空全填充PAD
            for (int i=off.value;i<off.value+len;i++)
            {//从off.value开始
                b[i] = pad;
            }
            off.value += len;
            return;
        }
        
        byte[] ret = str.getBytes(encoding);

        if (ret.length >= len)
        {//长度大于等于的len长度
            System.arraycopy(ret, 0, b, off.value, len);
        }
        else
        {
            System.arraycopy(ret, 0, b, off.value, ret.length);
            for (int i=off.value+ret.length;i<off.value+len;i++)
            {//从off.value+ret.length开始
                b[i] = pad;
            }
        }
        
        off.value += len;
    }
    
    /**
     * 插入一个定长的String,由str.getBytes().length来计算,以endValue结束<br>
     * 
     * @param b         字节数组
     * @param off       偏移量
     * @param str       字节串
     * @param endValue  结束符
     */
    public void putStringEnd(byte[] b, MInt off, String str, byte endValue)
    {
        if (Validates.isEmpty(str))
        {//为空仅填充endValue
            b[off.value] = endValue;
            off.value += 1;
            return;
        }
        
        byte[] ret = str.getBytes(encoding);
        System.arraycopy(ret, 0, b, off.value, ret.length);
        b[off.value + ret.length] = endValue;

        off.value += ret.length + 1;
    }

    
    /**
     * 插入一个定长的String,并以一个endValue结束<br>
     * 
     * @param b         字节数组
     * @param offset    偏移量
     * @param str       字节串
     * @param len       长度
     * @param endValue  结束符
     */
    public void putStringEnd(byte[] b, MInt off, String str, int len, byte endValue)
    {
        if (Validates.isEmpty(str))
        {//为空偏移len再填endValue
            b[off.value + len] = endValue;
            off.value += len + 1;
            return;
        }
        
        byte[] ret = str.getBytes(encoding);

        if (ret.length >= len)
            System.arraycopy(ret, 0, b, off.value, len);
        else
            System.arraycopy(ret, 0, b, off.value, ret.length);

        b[off.value + len] = endValue;
        off.value += len + 1;
    }
    
    
    /******************************************/
    // 以下方法为在给定的int型偏移位,给定的值,插入到指定的字节数组的方法
    /******************************************/

    public char getChar2(byte[] b, int off)
    {
        return isBigEndian ? (char) (((b[off + 1] & 0xFF) << 0) + ((b[off + 0] & 0xFF) << 8))
                            : (char) (((b[off + 0] & 0xFF) << 0) + ((b[off + 1] & 0xFF) << 8));
    }

    public short getShort(byte[] b, int off)
    {
        return (short) getShortUnsigned(b, off);
    }

    public int getShortUnsigned(byte[] b, int off)
    {
        return isBigEndian ? (((b[off + 1] & 0xFF) << 0) + ((b[off + 0] & 0xFF) << 8)) 
                            : (((b[off + 0] & 0xFF) << 0) + ((b[off + 1] & 0xFF) << 8));
    }

    public int getInt(byte[] b, int off)
    {
        return isBigEndian ? ((b[off + 3] & 0xFF) << 0) + ((b[off + 2] & 0xFF) << 8) + ((b[off + 1] & 0xFF) << 16) + ((b[off + 0] & 0xFF) << 24)
                            : ((b[off + 0] & 0xFF) << 0) + ((b[off + 1] & 0xFF) << 8) + ((b[off + 2] & 0xFF) << 16) + ((b[off + 3] & 0xFF) << 24);
    }

    public long getIntUnsigned(byte[] b, int off)
    {
        return getInt(b, off) & 0xFFFFFFFFL;
    }

    public float getFloat(byte[] b, int off)
    {
        int i = isBigEndian ? ((b[off + 3] & 0xFF) << 0) + ((b[off + 2] & 0xFF) << 8) + ((b[off + 1] & 0xFF) << 16) + ((b[off + 0] & 0xFF) << 24)
                            : ((b[off + 0] & 0xFF) << 0) + ((b[off + 1] & 0xFF) << 8) + ((b[off + 2] & 0xFF) << 16) + ((b[off + 3] & 0xFF) << 24);

        return Float.intBitsToFloat(i);
    }

    public long getLong(byte[] b, int off)
    {
        return isBigEndian ? ((b[off + 7] & 0xFFL) << 0) + ((b[off + 6] & 0xFFL) << 8) + ((b[off + 5] & 0xFFL) << 16) + ((b[off + 4] & 0xFFL) << 24)
                            + ((b[off + 3] & 0xFFL) << 32) + ((b[off + 2] & 0xFFL) << 40) + ((b[off + 1] & 0xFFL) << 48) + ((b[off + 0] & 0xFFL) << 56)
                            : ((b[off + 0] & 0xFFL) << 0) + ((b[off + 1] & 0xFFL) << 8) + ((b[off + 2] & 0xFFL) << 16) + ((b[off + 3] & 0xFFL) << 24)
                            + ((b[off + 4] & 0xFFL) << 32) + ((b[off + 5] & 0xFFL) << 40) + ((b[off + 6] & 0xFFL) << 48) + ((b[off + 7] & 0xFFL) << 56);
    }

    public double getDouble(byte[] b, int off)
    {
        long j = isBigEndian ? ((b[off + 7] & 0xFFL) << 0) + ((b[off + 6] & 0xFFL) << 8) + ((b[off + 5] & 0xFFL) << 16) + ((b[off + 4] & 0xFFL) << 24)
                              + ((b[off + 3] & 0xFFL) << 32) + ((b[off + 2] & 0xFFL) << 40) + ((b[off + 1] & 0xFFL) << 48) + ((b[off + 0] & 0xFFL) << 56)
                              : ((b[off + 0] & 0xFFL) << 0) + ((b[off + 1] & 0xFFL) << 8) + ((b[off + 2] & 0xFFL) << 16) + ((b[off + 3] & 0xFFL) << 24)
                              + ((b[off + 4] & 0xFFL) << 32) + ((b[off + 5] & 0xFFL) << 40) + ((b[off + 6] & 0xFFL) << 48) + ((b[off + 7] & 0xFFL) << 56);

        return Double.longBitsToDouble(j);
    }

    public String getString(byte[] b, int off, char val)
    {
        return getString(b, off, (byte)val);
    }
    
    public String getString(byte[] b, int off, byte val)
    {
        int i = off;
        int allLen = b.length;
        while (i < allLen)
        {
            if (b[i] == val)
                break;

            i++;
        }

        byte[] tmp = new byte[i - off];
        System.arraycopy(b, off, tmp, 0, i - off);

        return new String(tmp, encoding);
    }

    public String getString(byte[] b, int off, int len)
    {
        int i = 0;
        while (i < len)
        {
            if (off + i >= b.length)
                break;
            if (0 == b[off + i])
                break;
            i++;
        }

        byte[] tmp = new byte[i];
        System.arraycopy(b, off, tmp, 0, i);

        return new String(tmp, encoding);
    }

    public int putChar2(byte[] b, int off, char val)
    {
        if (isBigEndian)
        {
            b[off + 1] = (byte) (val >>> 0);
            b[off + 0] = (byte) (val >>> 8);
        }
        else
        {
            b[off + 0] = (byte) (val >>> 0);
            b[off + 1] = (byte) (val >>> 8);
        }

        return off + 2;
    }

    public int putShort(byte[] b, int off, short val)
    {
        if (isBigEndian)
        {
            b[off + 1] = (byte) (val >>> 0);
            b[off + 0] = (byte) (val >>> 8);
        }
        else
        {
            b[off + 0] = (byte) (val >>> 0);
            b[off + 1] = (byte) (val >>> 8);
        }

        return off + 2;
    }

    public int putShort(byte[] b, int off, int val)
    {
        return putShort(b, off, (short) val);
    }

    public int putInt(byte[] b, int off, int val)
    {
        if (isBigEndian)
        {
            b[off + 3] = (byte) (val >>> 0);
            b[off + 2] = (byte) (val >>> 8);
            b[off + 1] = (byte) (val >>> 16);
            b[off + 0] = (byte) (val >>> 24);
        }
        else
        {
            b[off + 0] = (byte) (val >>> 0);
            b[off + 1] = (byte) (val >>> 8);
            b[off + 2] = (byte) (val >>> 16);
            b[off + 3] = (byte) (val >>> 24);
        }

        return off + 4;
    }

    public int putInt(byte[] b, int off, long val)
    {
        return putInt(b, off, (int)val);
    }
    
    public int putFloat(byte[] b, int off, float val)
    {
        int i = Float.floatToIntBits(val);
        if (isBigEndian)
        {
            b[off + 3] = (byte) (i >>> 0);
            b[off + 2] = (byte) (i >>> 8);
            b[off + 1] = (byte) (i >>> 16);
            b[off + 0] = (byte) (i >>> 24);
        }
        else
        {
            b[off + 0] = (byte) (i >>> 0);
            b[off + 1] = (byte) (i >>> 8);
            b[off + 2] = (byte) (i >>> 16);
            b[off + 3] = (byte) (i >>> 24);
        }

        return off + 4;
    }

    public int putLong(byte[] b, int off, long val)
    {
        if (isBigEndian)
        {
            b[off + 7] = (byte) (val >>> 0);
            b[off + 6] = (byte) (val >>> 8);
            b[off + 5] = (byte) (val >>> 16);
            b[off + 4] = (byte) (val >>> 24);
            b[off + 3] = (byte) (val >>> 32);
            b[off + 2] = (byte) (val >>> 40);
            b[off + 1] = (byte) (val >>> 48);
            b[off + 0] = (byte) (val >>> 56);
        }
        else
        {
            b[off + 0] = (byte) (val >>> 0);
            b[off + 1] = (byte) (val >>> 8);
            b[off + 2] = (byte) (val >>> 16);
            b[off + 3] = (byte) (val >>> 24);
            b[off + 4] = (byte) (val >>> 32);
            b[off + 5] = (byte) (val >>> 40);
            b[off + 6] = (byte) (val >>> 48);
            b[off + 7] = (byte) (val >>> 56);
        }

        return off + 8;
    }

    public int putDouble(byte[] b, int off, double val)
    {
        long j = Double.doubleToLongBits(val);

        if (isBigEndian)
        {
            b[off + 7] = (byte) (j >>> 0);
            b[off + 6] = (byte) (j >>> 8);
            b[off + 5] = (byte) (j >>> 16);
            b[off + 4] = (byte) (j >>> 24);
            b[off + 3] = (byte) (j >>> 32);
            b[off + 2] = (byte) (j >>> 40);
            b[off + 1] = (byte) (j >>> 48);
            b[off + 0] = (byte) (j >>> 56);
        }
        else
        {
            b[off + 0] = (byte) (j >>> 0);
            b[off + 1] = (byte) (j >>> 8);
            b[off + 2] = (byte) (j >>> 16);
            b[off + 3] = (byte) (j >>> 24);
            b[off + 4] = (byte) (j >>> 32);
            b[off + 5] = (byte) (j >>> 40);
            b[off + 6] = (byte) (j >>> 48);
            b[off + 7] = (byte) (j >>> 56);
        }

        return off + 8;
    }

    public int putString(byte[] b, int off, String str)
    {
        if (Validates.isEmpty(str))
            return off;

        byte[] ret = str.getBytes(encoding);
        System.arraycopy(ret, 0, b, off, ret.length);
        return off + ret.length;
    }

    public int putString(byte[] b, int off, String str, int len)
    {
        if (Validates.isEmpty(str))
        {//为空仅偏移len
            return off + len;
        }
        
        byte[] ret = str.getBytes(encoding);

        if (ret.length >= len)
            System.arraycopy(ret, 0, b, off, len);
        else
            System.arraycopy(ret, 0, b, off, ret.length);

        return off + len;
    }
    
    public int putString(byte[] b, int off, Object val, int len, char pad)
    {
        return putString(b, off, String.valueOf(val), len, (byte)pad);
    }
    
    public int putString(byte[] b, int off, String str, int len, char pad)
    {
        return putString(b, off, str, len, (byte)pad);
    }
    
    public int putString(byte[] b, int off, String str, int len, byte pad)
    {
        if (Validates.isEmpty(str))
        {//为空全填充PAD
            for (int i=off;i<off+len;i++)
            {//从off开始
                b[i] = pad;
            }
            return off + len;
        }
        
        byte[] ret = str.getBytes(encoding);

        if (ret.length >= len)
        {//长度大于等于的len长度
            System.arraycopy(ret, 0, b, off, len);
        }
        else
        {//长度小于的补充PAD
            System.arraycopy(ret, 0, b, off, ret.length);
            for (int i=off+ret.length;i<off+len;i++)
            {//从off+ret.length开始
                b[i] = pad;
            }
        }
        
        return off + len;
    }

    public int putStringEnd(byte[] b, int off, String str, byte endValue)
    {
        if (Validates.isEmpty(str))
        {//为空仅填充endValue
            b[off] = endValue;
            return off + 1;
        }
        
        byte[] ret = str.getBytes(encoding);
        System.arraycopy(ret, 0, b, off, ret.length);
        b[off + ret.length] = endValue;

        return off + ret.length + 1;
    }

    public int putStringEnd(byte[] b, int off, String str, int len, byte endValue)
    {
        if (Validates.isEmpty(str))
        {//为空偏移len再填endValue
            b[off + len] = endValue;
            return off + len + 1;
        }
        
        byte[] ret = str.getBytes(encoding);

        if (ret.length >= len)
            System.arraycopy(ret, 0, b, off, len);
        else
            System.arraycopy(ret, 0, b, off, ret.length);

        b[off + len] = endValue;
        return off + len + 1;
    }
    
    /**********************************************************/
    // 以下方法为String和byte[]之间的转换和长度获取
    /**********************************************************/

    /** 获取编码后的字符串长度 */
    public int getByteLen(String str)
    {
        if (str == null)
            return 0;

        try
        {
            return str.getBytes(encoding).length;
        }
        catch (Exception e)
        {
            return str.getBytes().length;
        }
    }

    public String toString(byte[] bytes)
    {
        if (bytes == null)
            return null;

        int len = 0;
        for (int i = 0; i < bytes.length; i++)
        {
            if (bytes[i] == 0)
                break;

            len++;
        }

        return (len == 0)?_EMPTY_:new String(bytes, encoding);
    }

    public byte[] toBytes(short val)
    {
        byte[] b = new byte[2];
        putShort(b, 0, val);
        return b;
    }

    public byte[] toBytes(int val)
    {
        byte[] b = new byte[4];
        putInt(b, 0, val);
        return b;
    }

    public byte[] toBytes(long val)
    {
        byte[] b = new byte[8];
        putLong(b, 0, val);
        return b;
    }

    public byte[] toBytes(float val)
    {
        byte[] b = new byte[4];
        putFloat(b, 0, val);
        return b;
    }

    public byte[] toBytes(double val)
    {
        byte[] b = new byte[8];
        putDouble(b, 0, val);
        return b;
    }

    public byte[] toBytes(String str)
    {
        return (str == null)?new byte[0]:str.getBytes(encoding);
    }

    public byte[] toBytes(String str, int len)
    {
        if (str == null)
            return new byte[len];

        byte[] buf = str.getBytes(encoding);
        byte[] bytes = new byte[len];
        if (buf.length > len)
            System.arraycopy(buf, 0, bytes, 0, len);
        else
            System.arraycopy(buf, 0, bytes, 0, buf.length);

        return bytes;
    }

    public byte[] toBytesByIp(String ip)
    {
        byte[] b = new byte[4];
        putIp4(b, 0, ip);
        return b;
    }
    
    /*******************************************************************/
    //转化成HEX字符串之后，再转化为byte[]
    /*******************************************************************/
    
    /** 把每个字节转换成十六进制的字符串，再转换成byte[] */
    public static byte[] toHexBytes(byte[] b, LetterCase letter)
    {
        return toBytesASCII(Hexs.toHexString(b, letter));
    }
    
    /** 把短整型转化为4个字节的HEX字符串的byte[] */
    public byte[] toHexBytes(short val, LetterCase letter)
    {
        return toHexBytes(toBytes(val), letter);
    }
    
    /** 把整型转化为8个字节的HEX字符串的byte[] */
    public byte[] toHexBytes(int val, LetterCase letter)
    {
        return toHexBytes(toBytes(val), letter);
    }
    
    /** 把整型转化为只保留4个字节的HEX字符串的byte[] */
    public byte[] toHexBytesByShort(int val, LetterCase letter)
    {
        return toHexBytes(toBytes((short)val), letter);
    }
    
    /** 把短整型转化为4个字节的HEX字符串的byte[] */
    public void putHexBytes(byte[] b, int off, short val, LetterCase letter)
    {
        putBytes(b, off, toHexBytes(toBytes(val), letter));
    }
    
    /** 把整型转化为8个字节的HEX字符串的byte[] */
    public void putHexBytes(byte[] b, int off, int val, LetterCase letter)
    {
        putBytes(b, off, toHexBytes(toBytes(val), letter));
    }
    
    /** 把整型转化为只保留4个字节的HEX字符串的byte[] */
    public void putHexBytesByShort(byte[] b, int off, int val, LetterCase letter)
    {
        putBytes(b, off, toHexBytes(toBytes((short)val), letter));
    }

    /**********************************************************/
    // 以下方法静态方法byte[]处理方法
    /**********************************************************/
    
    /**
     * 字节数组转为字符数组，对byte进行0xFF操作
     * 
     * @param bytes     字节数组
     * @return          字符数组
     */
    public static char[] toCharArray(byte[] bytes)
    {
        char[] result = new char[bytes.length];
        for (int i=0;i<bytes.length;i++){
            result[i] = (char)(bytes[i] & 0xFF);
        }
        return result;
    }
    
    /**
     * 字节数组转为字符数组，对byte进行0xFF操作
     * 
     * @param bytes     字节数组
     * @param off       偏移量
     * @param len       长度
     * @return          字符数组
     */
    public static char[] toCharArray(byte[] bytes, int off, int len)
    {
        Asserts.as((bytes != null && bytes.length >= off+len)?null:"字节数组转为字符数组时，长度不满足要求");
        
        char[] result = new char[len];
        for (int i=0;i<len;i++,off++){
            result[i] = (char)(bytes[off] & 0xFF);
        }
        return result;
    }
    
    /**
     * 字节数组无编码，直接转化为字符数组后转为字符串
     * 
     * @param bytes     字节数组
     * @return          字符串
     */
    public static String toStringASCII(byte[] bytes)
    {
        return new String(toCharArray(bytes));
    }
    
    /**
     * 字节数组无编码，直接转化为字符数组后转为字符串
     * 
     * @param bytes     字节数组
     * @param off       偏移量
     * @param len       长度
     * @return          字符串
     */
    public static String toStringASCII(byte[] bytes, int off, int len)
    {
        return new String(toCharArray(bytes, off, len));
    }
    
    /**
     * 指定字节缓冲和字符集生成字符串
     * 
     * @param buf                           字节缓冲
     * @param charset                       字符集
     * @return                              字符串
     * @throws CharacterCodingException     字符集异常
     */
    public static String toString(ByteBuffer buf, Charset charset) throws CharacterCodingException
    {
        CharsetDecoder decoder = charset.newDecoder();
        decoder.onMalformedInput(CodingErrorAction.REPORT);
        decoder.onUnmappableCharacter(CodingErrorAction.REPORT);
        return decoder.decode(buf).toString();
    }
    
    /** 获取指定编码的bytes，不抛UnsupportedEncodingException异常，规避多加异常代码 */
    public static byte[] toBytes(String str, String encoding)
    {
        if (str == null)
            return new byte[0];

        try
        {
            return str.getBytes(encoding);
        }
        catch (UnsupportedEncodingException e)
        {
            throw Asserts.exception("不支持的编码格式[" + encoding + "]");
        }
    }

    /** 获取[GBK],bytes，不抛UnsupportedEncodingException异常，规避多加异常代码 */
    public static byte[] toBytesGBK(String str)
    {
        return (str == null)?new byte[0]:str.getBytes(_GBK_C_);
    }

    /** 获取[UTF-8]bytes，不抛UnsupportedEncodingException异常，规避多加异常代码 */
    public static byte[] toBytesUTF8(String str)
    {
        return (str == null)?new byte[0]:str.getBytes(_UTF_8_C_);
    }
    

    /** 获取全ASCII字符串转化的bytes，有多字节的抛出异常 */
    public static byte[] toBytesASCIIException(String str)
    {
        byte[] b = new byte[str.length()];
        for (int i=0;i<b.length;i++)
        {
            char c = str.charAt(i);
            Asserts.as(c <= 255?null:"存在非ASCII字符，不支持");

            b[i] = (byte)c;
        }
        return b;
    }
    
    /** 获取全ASCII字符串转化的bytes，多字节强制转为单字节 */
    public static byte[] toBytesASCII(String str)
    {
        byte[] b = new byte[str.length()];
        for (int i=0;i<b.length;i++)
        {
            b[i] = (byte)str.charAt(i);
        }
        return b;
    }
    
    /** 获取long转化为字符串后转化的bytes */
    public static byte[] toBytesASCII(long val)
    {
        return toBytesASCII(String.valueOf(val));
    }
    
    /** 获取int转化为字符串后转化的bytes */
    public static byte[] toBytesASCII(int val)
    {
        return toBytesASCII(String.valueOf(val));
    }

    /**
     * 填充指定字节
     * 
     * @param b         字节数组
     * @param pad       填充字节
     */
    public static void fill(byte[] b, byte pad)
    {
        for (int i=0;i<b.length;i++)
        {
            b[i] = pad;
        }
    }
    
    /**
     * 填充指定字节，从指定的起始位置开始
     * 
     * @param b         字节数组
     * @param off       起始位置
     * @param pad       填充字节
     */
    public static void fill(byte[] b, int off, byte pad)
    {
        for (int i=off;i<b.length;i++)
        {
            b[i] = pad;
        }
    }
    
    /**
     * 填充指定字节，从指定的起始位置开始，到指定的长度中去
     * 
     * @param b         字节数组
     * @param off       起始位置
     * @param pad       填充字节
     * @param len       长度
     */
    public static void fill(byte[] b, int off, byte pad, int len)
    {
        for (int i=off;i<b.length;i++)
        {
            if (i == (off + len))
                break;
            
            b[i] = pad;
        }
    }
    
    /**
     * 填充指定字节，到byte[]的指定的起始位置和长度中去
     * 
     * @param b         字节数组
     * @param off       起始位置
     * @param pad       填充字节
     * @param len       长度
     */
    @Deprecated
    public static void fillBytes(byte[] b, int off, byte pad, int len)
    {
        fill(b, off, pad, len);
    }

    /** 获取指定编码的byte长度 */
    public static int getByteLen(String str, String encoding)
    {
        return toBytes(str, encoding).length;
    }
    
    /**
     * 获取源数组从起始位置后面的字节数组
     * 
     * @param b         源字节数组
     * @param off       源字节数组起始位置
     * @return          新的字节数组
     */
    public static byte[] getBytes(byte[] b, int off)
    {
        byte[] bytes = new byte[b.length - off];
        System.arraycopy(b, off, bytes, 0, b.length - off);

        return bytes;
    }

    /**
     * 获取指定长度的字节数组，从off计算，如果源数组不足，后补0，不补0方法请使用getBytesAvailable
     * 
     * @param b         源字节数组
     * @param off       源字节数组起始位置
     * @param len       指定的长度
     * @return          新的字节数组
     */
    public static byte[] getBytes(byte[] b, int off, int len)
    {
        byte[] bytes = new byte[len];
        if (len + off <= b.length)
            System.arraycopy(b, off, bytes, 0, len);
        else
            System.arraycopy(b, off, bytes, 0, b.length - off);

        return bytes;
    }
    
    /**
     * 获取指定结尾字符的字节数组
     * 
     * @param b         源字节数组
     * @param off       源字节数组起始位置
     * @param val       指定的配对字符
     * @return          获取到的字节数组
     */
    public static byte[] getBytes(byte[] b, int off, char val)
    {
        return getBytes(b, off, (byte)val);
    }

    /**
     * 获取指定结尾字符的字节数组
     * 
     * @param b         源字节数组
     * @param off       源字节数组起始位置
     * @param val       指定的配对字节
     * @return          获取到的字节数组
     */
    public static byte[] getBytes(byte[] b, int off, byte val)
    {
        int len = next(b, off, val) - off - 1;
        return getBytes(b, off, len);
    }
    
    /**
     * 获取指定结尾字符的字节数组
     * 
     * @param b         源字节数组
     * @param off       源字节数组起始位置
     * @param val       指定的配对字符
     * @return          获取到的字节数组
     */
    public static byte[] getBytes(byte[] b, MInt off, char val)
    {
        return getBytes(b, off, (byte)val);
    }
    
    /**
     * 获取指定结尾字节的字节数组
     * 
     * @param b         源字节数组
     * @param off       源字节数组起始位置
     * @param val       指定的配对字节
     * @return          获取到的字节数组
     */
    public static byte[] getBytes(byte[] b, MInt off, byte val)
    {
        int offset = off.value;
        off.value = next(b, offset, val);
        
        return getBytes(b, offset, off.value - offset - 1);
    }
    
    /**
     * 获取可用的字节数组，定长请使用getBytes，从off计算，如果如果源数组长度大于等于len则取len，少于len，则取实际b.length-
     * off长度
     * 
     * @param b         源字节数组
     * @param off       起始位置
     * @param len       要求的长度
     * @return          byte[] 可用的字节数组
     */
    public static byte[] getBytesAvailable(byte[] b, int off, int len)
    {
        if (len + off <= b.length)
        {
            byte[] bytes = new byte[len];
            System.arraycopy(b, off, bytes, 0, len);
            return bytes;
        }
        else
        {
            byte[] bytes = new byte[b.length - off];
            System.arraycopy(b, off, bytes, 0, b.length - off);
            return bytes;
        }
    }
    
    /**
     * 判断字节数组是否有前缀
     * 
     * @param b         字节数组
     * @param prefix    字节前缀
     * @return          ＝true表示有前缀
     */
    public static boolean isPrefix(byte[] b, byte[] prefix)
    {
        return match(b, 0, prefix) != -1;
    }
    
    /**
     * 判断字节数组是否从偏移位匹配到指定字节数组
     * 
     * @param b         字节数组
     * @param off       字节数组偏移位
     * @param match     匹配的字节数组
     * @return           =-1表示未匹配成功，
     *                   !=-1表示匹配成功，off向后偏移match.length
     */
    public static int match(byte[] b, int off, byte[] match)
    {
        Asserts.notNull(match, "match");
        
        if (b == null || b.length < match.length + off)
            return -1;
        
        for (int i=0;i<match.length;i++,off++)
        {
            if (b[off] != match[i])
                return -1;
        }
        
        return off;
    }
    
    /**********************************************************/
    // 以下方法为判断是否图片格式，当前支持jpg,gif,png
    /**********************************************************/

    /**
     * 判断是否PNG 格式，要求长度大于8，前4字节为0x89 0x50 0x4E 0x47
     * 
     * @param b 字节数组
     * @return =true表示PNG
     */
    public static boolean isPNG(byte[] b)
    {
        return (b == null || b.length < 8)?false:isPrefix(b, _PNG_HDR_);
    }

    /**
     * 判断是否JPG格式，要求长度大于4，前2字节为0xFF 0xD8
     * 
     * @param b 字节数组
     * @return =true表示JPG
     */
    public static boolean isJPG(byte[] b)
    {
        return (b == null || b.length < 4)?false:isPrefix(b, _JPG_HDR_);
    }

    /**
     * 判断是否GIF格式，要求长度大于6，前3字节为0x47 0x49 0x46
     * 
     * @param b 字节数组
     * @return =true表示GIF
     */
    public static boolean isGIF(byte[] b)
    {
        return (b == null || b.length < 6)?false:isPrefix(b, _GIF_HDR_);
    }
    
    /**
     * 图片压缩成PNG格式
     * 
     * @param data　        图片数据
     * @param width         压缩后宽度
     * @param height        压缩后高度
     * @throws IOException  IO异常
     */
    public static byte[] resizePNG(byte[] data, int width, int height) throws IOException
    {
        Asserts.notNull(data);
        
        ByteArrayInputStream input = new ByteArrayInputStream(data);
        BufferedImage src = ImageIO.read(input);
        
        BufferedImage buffImg = null;   
        if(src.isAlphaPremultiplied())//判断alpha通道是否需要变为透明的
            buffImg = new BufferedImage(width, height, BufferedImage.TRANSLUCENT);  
        else  
            buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);  
     
        Image image = src.getScaledInstance(width, height, Image.SCALE_SMOOTH);//压缩时作平滑处理
        
        Graphics2D  g = (Graphics2D) buffImg.getGraphics();
        g.drawImage(image, 0, 0, width, height, Color.white, null); //Color.white防止背景有时变黑
        g.dispose();
         
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        ImageIO.write(buffImg, _PNG_, output);
        
        return output.toByteArray();
    }
    
    /**********************************************************/
    // 以下方法为判断是否BOM
    /**********************************************************/
    
    /** 是否是UTF8格式//EF BB BF */
    public static boolean isUTF8BOM(byte[] b)
    {
        return isPrefix(b, _BOM_UTF8_);
    }
    
    /** 是否是UTF16BE格式//FE FF */
    public static boolean isUTF16BEBOM(byte[] b)
    {
        return isPrefix(b, _BOM_UTF16BE_);
    }
    
    /** 是否是UTF16LE格式//FF FE */
    public static boolean isUTF16LEBOM(byte[] b)
    {
        return isPrefix(b, _BOM_UTF16LE_);
    }
    
    /** 是否是UTF32BE格式//FF FE 00 00 */
    public static boolean isUTF32LEBOM(byte[] b)
    {
        return isPrefix(b, _BOM_UTF32LE_);
    }
    
    /** 是否是UTF16BE格式 00 00 FE FF */
    public static boolean isUTF32BEBOM(byte[] b)
    {
        return isPrefix(b, _BOM_UTF32BE_);
    }
    

    /**********************************************************/
    // 在byte[]中向前向后寻找下一个字符位置
    /**********************************************************/
    
    /**
     * 向后寻找指定字符的位置，没找到off移动到最后
     * 
     * @param b         字节数组
     * @param off       偏移量
     * @param val       字符
     * @return          找到字符的偏移量
     */
    public static final int next(byte[] b, int off, char val)
    {
        return next(b, off, (byte)val);
    }
    
    /**
     * 向后寻找指定字节的位置，没找到off移动到最后
     * 
     * @param b         字节数组
     * @param off       偏移量
     * @param val       字节
     * @return          找到字符的偏移量
     */
    public static final int next(byte[] b, int off, byte val)
    {
        int len = b.length;
        while (off < len)
        {
            if (b[off++] == val)
                return off;
        }
        return off;
    }
    
    /**
     * 向后寻找换行符的位置，没找到off移动到最后
     * 
     * @param b         字节数组
     * @param off       偏移量
     * @return          找到换行符的偏移量
     */
    public static final int nextLF(byte[] b, int off)
    {
        return next(b, off, '\n');
    }
    
    /**
     * 向后寻找换行符和指定字符之一的位置，没找到off移动到最后
     * 
     * @param b         字节数组
     * @param off       偏移量
     * @param val       字符
     * @return          找到换行符或指定字符的偏移量
     */
    public static final int nextLF(byte[] b, int off, char val)
    {
        int len = b.length;
        while (off < len)
        {
            byte c = b[off++];
            if (c == val || c == '\n')
                return off;
        }
        return off;
    }
    
    /**
     * 向前寻找指定字符位置，没找到off移动到-1
     * 
     * @param b         字节数组
     * @param off       偏移量
     * @param val       字符
     * @return          找到指定字符的偏移量
     */
    public static final int prev(byte[] b, int off, final char val)
    {
        if (off >= b.length)
            off = b.length-1;
        
        while (off >= 0)
        {
            if (b[off--] == val)
                return off;
        }
        return off;
    }

    /**
     * 向前寻找换行符的位置，没找到off移动到-1
     * 
     * @param b         字节数组
     * @param off       偏移量
     * @return          找到指定字符的偏移量
     */
    public static final int prevLF(byte[] b, int off)
    {
        return prev(b, off, '\n');
    }

    /**
     * 向前寻找换行符和指定字符之一的位置，没找到off移动到-1
     * 
     * @param b         字节数组
     * @param off       偏移量
     * @param val       字符
     * @return          找到换行符或指定字符的偏移量
     */
    public static final int prevLF(byte[] b, int off, final char val)
    {
        if (off >= b.length)
            off = b.length-1;
        
        while (off >= 0)
        {
            byte c = b[off--];
            if (c == val || c == '\n')
                return off;
        }
        return off;
    }
    
    /***************************************************************************************************/
    // 静态方法写入字节&字节数组
    /***************************************************************************************************/

    public static int putBOMUTF8(byte[] b, int off)
    {
        b[off + 0] = (byte) 0xEF;
        b[off + 1] = (byte) 0xBB;
        b[off + 2] = (byte) 0xBF;

        return off + 3;
    }

    public static int putBOMUTF16LE(byte[] b, int off)
    {
        b[off + 0] = (byte) 0xFF;
        b[off + 1] = (byte) 0xFE;

        return off + 2;
    }

    public static int putBOMUTF16BE(byte[] b, int off)
    {
        b[off + 0] = (byte) 0xFE;
        b[off + 1] = (byte) 0xFF;

        return off + 2;
    }

    public static int putBOMUTF32LE(byte[] b, int off)
    {
        b[off + 0] = (byte) 0xFF;
        b[off + 1] = (byte) 0xFE;
        b[off + 2] = (byte) 0x00;
        b[off + 3] = (byte) 0x00;

        return off + 4;
    }

    public static int putBOMUTF32BE(byte[] b, int off)
    {
        b[off + 0] = (byte) 0x00;
        b[off + 1] = (byte) 0x00;
        b[off + 2] = (byte) 0xFE;
        b[off + 3] = (byte) 0xFF;

        return off + 4;
    }

    public static int putByte(byte[] b, int off, byte val)
    {
        b[off] = val;

        return off + 1;
    }
    
    public static int putByte(byte[] b, int off, int val)
    {
        b[off] = (byte)val;
        return off + 1;
    }

    public static int putBytes(byte[] b, int off, byte[] src)
    {
        if (src == null || src.length == 0)
            return off;
        
        System.arraycopy(src, 0, b, off, src.length);
        return off + src.length;
    }

    public static int putBytes(byte[] b, int off, byte[] src, int len)
    {
        if (src == null || src.length == 0)
        {//为空仅偏移
            return off + len;
        }
        
        System.arraycopy(src, 0, b, off, len);
        return off + len;
    }
    
    public static int putBoolean(byte[] b, int off, boolean val)
    {
        b[off] = (byte) (val ? 1 : 0);

        return off + 1;
    }

    public static int putChar1(byte[] b, int off, char val)
    {
        b[off + 0] = (byte) (val & 0xFF);

        return off + 1;
    }
    
    /**
     * 插入UTF-8的BOM（三个字节EF BB BF）
     * 
     * @param b         字节数组
     * @param off       偏移量
     */
    public static void putBOMUTF8(byte[] b, MInt off)
    {
        off.value = putBOMUTF8(b, off.value);
    }

    /**
     * 插入UTF16 LE的BOM（两个字节FF FE）
     * 
     * @param b         字节数组
     * @param off       偏移量
     */
    public static void putBOMUTF16LE(byte[] b, MInt off)
    {
        off.value = putBOMUTF16LE(b, off.value);
    }

    /**
     * 插入UTF16 BE的BOM（两个字节FE FF）
     * 
     * @param b         字节数组
     * @param off       偏移量
     */
    public static void putBOMUTF16BE(byte[] b, MInt off)
    {
        off.value = putBOMUTF16BE(b, off.value);
    }

    /**
     * 插入UTF32 LE的BOM（四个字节FF FE 00 00）
     * 
     * @param b         字节数组
     * @param offset    偏移量
     */
    public static void putBOMUTF32LE(byte[] b, MInt off)
    {
        off.value = putBOMUTF32LE(b, off.value);
    }

    /**
     * 插入UTF32 BE的BOM（四个字节00 00 FE FF）
     * 
     * @param b         字节数组
     * @param off       偏移量
     */
    public static void putBOMUTF32BE(byte[] b, MInt off)
    {
        off.value = putBOMUTF32BE(b, off.value);
    }

    /**
     * 插入一个不定长字节数组<br>
     * 
     * @param b         字节数组
     * @param off       偏移量
     * @param src       要插入的字符数组
     */
    public static void putBytes(byte[] b, MInt off, byte[] src)
    {
        if (src == null || src.length == 0)
            return;

        System.arraycopy(src, 0, b, off.value, src.length);
        off.value += src.length;
    }

    /**
     * 插入一个定长字节数组，如果src为null或为空取new byte[len]<br>
     * 
     * @param b         字节数组
     * @param off       偏移量
     * @param src       要插入的字符数组
     * @param len       长度
     */
    public static void putBytes(byte[] b, MInt off, byte[] src, int len)
    {
        if (len <= 0)
            return;

        if (src == null || src.length == 0)
        {//为空仅偏移
            off.value += len;
            return;
        }

        System.arraycopy(src, 0, b, off.value, len);
        off.value += len;
    }
    
    /**
     * 插入一个字节
     * 
     * @param b         字节数组
     * @param off       偏移量
     * @param val       byte
     */
    public static void putByte(byte[] b, MInt off, byte val)
    {
        b[off.value++] = val;
    }
    
    /**
     * 插入一个字节
     * 
     * @param b         字节数组
     * @param off       偏移量
     * @param val       int转为byte
     */
    public static void putByte(byte[] b, MInt off, int val)
    {
        b[off.value++] = (byte)val;
    }

    /**
     * 插入一个boolean<br>
     * 
     * @param b         字节数组
     * @param off       偏移量
     * @param val       booelan
     */
    public static void putBoolean(byte[] b, MInt off, boolean val)
    {
        b[off.value++] = (byte)(val ? 1 : 0);
    }

    /**
     * 插入一个 <b>单字节</b> 的char<br>
     * 
     * @param b         字节数组
     * @param off       偏移量
     * @param val       单字节char
     */
    public static void putChar1(byte[] b, MInt off, char val)
    {
        b[off.value++] = (byte)val;
    }
    
    public static int putIp4(byte[] b, int off, String value)
    {
        if (value == null)
            value = "0.0.0.0";

        String[] strs = value.split("\\.");
        if (strs == null || strs.length != 4)
            return off;

        for (int i = 0; i < strs.length; i++)
        {
            b[off + i] = (byte) Integer.parseInt(strs[i]);
        }

        return off + 4;
    }

    public static int putMac(byte[] b, int off, String value)
    {
        if (value == null)
            value = "00:00:00:00:00:00:00";

        byte[] val = Hexs.toBytes(value, ":");
        for (int i = 0; i < val.length; i++)
        {
            b[off + i] = val[i];
        }

        return off + 6;
    }
    
    /**
     * 插入一个Ip4<br>
     * 
     * @param b         字节数组
     * @param off       偏移量
     * @param val       int
     */
    public static void putIp4(byte[] b, MInt off, String val)
    {
         off.value = putIp4(b, off.value, val);
    }

    /**
     * 插入一个Mac<br>
     * 
     * @param b         字节数组
     * @param off       偏移量
     * @param val       int
     */
    public static void putMac(byte[] b, MInt off, String val)
    {
        off.value = putMac(b, off.value, val);
    }
    
    /***************************************************************************************************/
    // 静态方法获取字节&字节数组
    /***************************************************************************************************/

    public static byte getByte(byte[] b, int off)
    {
        return b[off];
    }
    
    public static int getByteUnsigned(byte[] b, int off)
    {
        return b[off] & 0xFF;
    }

    public static boolean getBoolean(byte[] b, int off)
    {
        return b[off] != 0;
    }

    public static char getChar1(byte[] b, int off)
    {
        return (char) ((b[off + 0] & 0xFF));
    }
    
    /**
     * 从字节数组b中 根据偏移量offset读起一个byte<br>
     * 
     * @param b         字节数组
     * @param off       可变偏移量
     * @return byte     得到byte
     */
    public static byte getByte(byte[] b, MInt off)
    {
        return b[off.value++];
    }
    
    /**
     * 从字节数组b中 根据偏移量offset读起一个byte<br>
     * 
     * @param b         字节数组
     * @param off       可变偏移量
     * @return int      得到byte的无符号整型(0-255)
     */
    public static int getByteUnsigned(byte[] b, MInt off)
    {
        return b[off.value++] & 0xFF;
    }

    /**
     * 从字节数组b中 根据偏移量offset读起一个boolean<br>
     * 
     * @param b         字节数组
     * @param off       可变偏移量
     * @return boolean  得到boolean
     */
    public static boolean getBoolean(byte[] b, MInt off)
    {
        return b[off.value++] != 0;
    }

    /**
     * 从字节数组b中 根据偏移量offset读起一个 <b>单字节</b> 的char<br>
     * 
     * @param b         字节数组
     * @param off       可变偏移量
     * @return char     得到单字节的char
     */
    public static char getChar1(byte[] b, MInt off)
    {
        return getChar1(b, off.value++);
    }
    
    /**
     * 从字节数组b中 根据偏移量offset读起一个定长为len的byte[]<br>
     * 
     * @param b         字节数组
     * @param off       偏移量
     * @param len       读起的长度
     * @return          返回一个byte[]
     */
    public static byte[] getBytes(byte[] b, MInt off, int len)
    {
        int offset = off.value;

        byte[] bytes = new byte[len];
        if (len + offset <= b.length)
            System.arraycopy(b, offset, bytes, 0, len);
        else
            System.arraycopy(b, offset, bytes, 0, b.length - offset);

        off.value += len;
        return bytes;
    }

    /**
     * 从字节数组b中 根据偏移量offset读起一个到b末端的byte[]<br>
     * 
     * @param b         字节数组
     * @param off       偏移量
     * @return          返回一个byte[]
     */
    public static byte[] getBytes(byte[] b, MInt off)
    {
        int offset = off.value;
        byte[] bytes = new byte[b.length - offset];
        System.arraycopy(b, offset, bytes, 0, b.length - offset);

        off.value += bytes.length;
        return bytes;
    }
    
    public static String getIp4(byte[] b, int off)
    {
        StringBuilder strb = new StringBuilder();

        strb.append(b[off + 0] & 0xFF).append(".");
        strb.append(b[off + 1] & 0xFF).append(".");
        strb.append(b[off + 2] & 0xFF).append(".");
        strb.append(b[off + 3] & 0xFF);

        return strb.toString();
    }

    public static String getMac(byte[] b, int off)
    {
        StringBuilder strb = new StringBuilder();

        for (int i = 0; i < 6; i++)
        {
            if (i != 0)
                strb.append(":");

            String str = Integer.toString((b[off + i] & 0xff) + 0x100, 16).substring(1);
            strb.append(str);
        }

        return strb.toString();
    }
    

    /**
     * 从字节数组b中 根据偏移量offset读起一个v4的IP地址<br>
     * 
     * @param b         字节数组
     * @param off       偏移量
     * @return          返回一个192.168.0.1的IP地址
     */
    public static String getIp4(byte[] b, MInt off)
    {
        int offset = off.value;
        off.value += 4;

        return getIp4(b, offset);
    }

    /**
     * 从字节数组b中 根据偏移量offset读起一个Mac地址<br>
     * 
     * @param b         字节数组
     * @param off       偏移量
     * @return          返回一个EA:12:DE:35:FE:87的MAC地址
     */
    public static String getMac(byte[] b, MInt off)
    {
        int offset = off.value;
        off.value += 6;

        return getMac(b, offset);
    }
}